#include "bsp_flash.h"
#ifdef CHIP_TYPE_F4
static uint32_t GetSector(uint32_t Address)
{
    uint32_t sector = 0;

    if((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0))
    {
        sector = FLASH_SECTOR_0;
    }
    else if((Address < ADDR_FLASH_SECTOR_2) && (Address >= ADDR_FLASH_SECTOR_1))
    {
        sector = FLASH_SECTOR_1;
    }
    else if((Address < ADDR_FLASH_SECTOR_3) && (Address >= ADDR_FLASH_SECTOR_2))
    {
        sector = FLASH_SECTOR_2;
    }
    else if((Address < ADDR_FLASH_SECTOR_4) && (Address >= ADDR_FLASH_SECTOR_3))
    {
        sector = FLASH_SECTOR_3;
    }
    else if((Address < ADDR_FLASH_SECTOR_5) && (Address >= ADDR_FLASH_SECTOR_4))
    {
        sector = FLASH_SECTOR_4;
    }
    else if((Address < ADDR_FLASH_SECTOR_6) && (Address >= ADDR_FLASH_SECTOR_5))
    {
        sector = FLASH_SECTOR_5;
    }
    else if((Address < ADDR_FLASH_SECTOR_7) && (Address >= ADDR_FLASH_SECTOR_6))
    {
        sector = FLASH_SECTOR_6;
    }
    else if((Address < ADDR_FLASH_SECTOR_8) && (Address >= ADDR_FLASH_SECTOR_7))
    {
        sector = FLASH_SECTOR_7;
    }
#if defined(FLASH_SECTOR_8)
    else if((Address < ADDR_FLASH_SECTOR_9) && (Address >= ADDR_FLASH_SECTOR_8))
    {
        sector = FLASH_SECTOR_8;
    }
#endif
#if defined(FLASH_SECTOR_9)
    else if((Address < ADDR_FLASH_SECTOR_10) && (Address >= ADDR_FLASH_SECTOR_9))
    {
        sector = FLASH_SECTOR_9;
    }
#endif
#if defined(FLASH_SECTOR_10)
    else if((Address < ADDR_FLASH_SECTOR_11) && (Address >= ADDR_FLASH_SECTOR_10))
    {
        sector = FLASH_SECTOR_10;
    }
#endif
#if defined(FLASH_SECTOR_11)
    else if((Address < ADDR_FLASH_SECTOR_12) && (Address >= ADDR_FLASH_SECTOR_11))
    {
        sector = FLASH_SECTOR_11;
    }
#endif
#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx)|| defined(STM32F439xx) || defined(STM32F469xx) || defined(STM32F479xx)
    else if((Address < ADDR_FLASH_SECTOR_13) && (Address >= ADDR_FLASH_SECTOR_12))
    {
        sector = FLASH_SECTOR_12;
    }
    else if((Address < ADDR_FLASH_SECTOR_14) && (Address >= ADDR_FLASH_SECTOR_13))
    {
        sector = FLASH_SECTOR_13;
    }
    else if((Address < ADDR_FLASH_SECTOR_15) && (Address >= ADDR_FLASH_SECTOR_14))
    {
        sector = FLASH_SECTOR_14;
    }
    else if((Address < ADDR_FLASH_SECTOR_16) && (Address >= ADDR_FLASH_SECTOR_15))
    {
        sector = FLASH_SECTOR_15;
    }
    else if((Address < ADDR_FLASH_SECTOR_17) && (Address >= ADDR_FLASH_SECTOR_16))
    {
        sector = FLASH_SECTOR_16;
    }
    else if((Address < ADDR_FLASH_SECTOR_18) && (Address >= ADDR_FLASH_SECTOR_17))
    {
        sector = FLASH_SECTOR_17;
    }
    else if((Address < ADDR_FLASH_SECTOR_19) && (Address >= ADDR_FLASH_SECTOR_18))
    {
        sector = FLASH_SECTOR_18;
    }
    else if((Address < ADDR_FLASH_SECTOR_20) && (Address >= ADDR_FLASH_SECTOR_19))
    {
        sector = FLASH_SECTOR_19;
    }
    else if((Address < ADDR_FLASH_SECTOR_21) && (Address >= ADDR_FLASH_SECTOR_20))
    {
        sector = FLASH_SECTOR_20;
    }
    else if((Address < ADDR_FLASH_SECTOR_22) && (Address >= ADDR_FLASH_SECTOR_21))
    {
        sector = FLASH_SECTOR_21;
    }
    else if((Address < ADDR_FLASH_SECTOR_23) && (Address >= ADDR_FLASH_SECTOR_22))
    {
        sector = FLASH_SECTOR_22;
    }
    else /* (Address < FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_23) */
    {
        sector = FLASH_SECTOR_23;
    }
#endif
    return sector;
}

#endif
#ifdef CHIP_TYPE_L4
static uint32_t GetPage(uint32_t Addr)
{
    uint32_t page = 0;
    
    if(Addr < (FLASH_BASE + FLASH_BANK_SIZE))
    {
        /* Bank 1 */
        page = (Addr - FLASH_BASE) / FLASH_PAGE_SIZE;
    }
    else
    {
        /* Bank 2 */
        page = (Addr - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE;
    }
    
    return page;
}

static uint32_t GetNPage(uint32_t Addr, uint32_t Len)
{
    uint32_t Spage, Epage;
    
    Spage = GetPage(Addr);
    Epage = GetPage(Addr + Len - 1);
    
    return (Epage - Spage + 1);
}
static uint32_t GetBank(uint32_t Addr)
{
    uint32_t bank = 0;
    
    if(READ_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_FB_MODE) == 0)
    {
        /* No Bank swap */
        if(Addr < (FLASH_BASE + FLASH_BANK_SIZE))
        {
            bank = FLASH_BANK_1;
        }
        else
        {
            bank = FLASH_BANK_2;
        }
    }
    else
    {
        /* Bank swap */
        if(Addr < (FLASH_BASE + FLASH_BANK_SIZE))
        {
            bank = FLASH_BANK_2;
        }
        else
        {
            bank = FLASH_BANK_1;
        }
    }
    
    return bank;
}

#endif
#ifdef CHIP_TYPE_L1
static uint32_t GetPage(uint32_t Addr)
{
    return (Addr - FLASH_BASE) / FLASH_PAGE_SIZE;
}

static uint32_t GetNPage(uint32_t Addr, uint32_t Len)
{
    uint32_t Spage, Epage;
    
    Spage = GetPage(Addr);
    Epage = GetPage(Addr + Len - 1);
    
    return (Epage - Spage + 1);
}

#endif
/**
 * Read data from flash.
 * @note This operation's units is word.
 *
 * @param addr flash address
 * @param buf buffer to store read data
 * @param size read bytes size
 *
 * @return result
 */
int stm32_flash_read(uint32_t addr, uint8_t *buf, size_t size)
{
    size_t i;
    if ((addr + size) > STM32_FLASH_END_ADDRESS)
    {
        return -1;
    }
	__disable_irq();
    for (i = 0; i < size; i++, buf++, addr++)
    {
        *buf = *(uint8_t *) addr;
    }
	__enable_irq();
    return 0;
}

/**
 * Write data to flash.
 * @note This operation's units is word.
 * @note This operation must after erase. @see flash_erase.
 *
 * @param addr flash address
 * @param buf the write data buffer
 * @param size write bytes size
 *
 * @return result
 */
int stm32_flash_write(uint32_t addr, const uint8_t *buf, size_t size)
{
    int result      = FLASH_OK;
    uint32_t end_addr = addr + size;
    uint32_t written_size = 0;
    uint32_t write_size = 0;

    if ((end_addr) > STM32_FLASH_END_ADDRESS)
    {
        return FLASH_ERR;
    }

    if (size < 1)
    {
        return FLASH_ERR;
    }
	 __disable_irq();
#ifdef CHIP_TYPE_L1
	if(addr+written_size>=DATA_EEPROM_START_ADDR&&
				addr+written_size<=DATA_EEPROM_END_ADDR)
	{
		HAL_FLASHEx_DATAEEPROM_Unlock();
	}
#else
	HAL_FLASH_Unlock();
#endif
#ifdef CHIP_TYPE_F4 
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);

    while (written_size < size)
    {
        if (((addr + written_size) % 4 == 0) && (size - written_size >= 4))
        {
            if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr + written_size, *((uint32_t *)(buf + written_size))) == HAL_OK)
            {
                if (*(uint32_t *)(addr + written_size) != *(uint32_t *)(buf + written_size))
                {
                    result = FLASH_ERR;
                    break;
                }
            }
            else
            {
                result = FLASH_ERR;
                break;
            }
            write_size = 4;
        }
        else if (((addr + written_size) % 2 == 0) && (size - written_size >= 2))
        {
            if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, addr + written_size, *((uint16_t *)(buf + written_size))) == HAL_OK)
            {
                if (*(uint16_t *)(addr + written_size) != *(uint16_t *)(buf + written_size))
                {
                    result = FLASH_ERR;
                    break;
                }
            }
            else
            {
                result = FLASH_ERR;
                break;
            }
            write_size = 2;
        }
        else
        {
            if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, addr + written_size, *((uint8_t *)(buf + written_size))) == HAL_OK)
            {
                if (*(uint8_t *)(addr + written_size) != *(uint8_t *)(buf + written_size))
                {
                    result = FLASH_ERR;
                    break;
                }
            }
            else
            {
                result = FLASH_ERR;
                break;
            }
            write_size = 1;
        }

        written_size += write_size;
    }
#endif
#ifdef CHIP_TYPE_L4
	uint64_t IsrDataToPrg_64=0xffffffffffffffff;
	int i=0;
	while (written_size < size)
	{
		i=0;
		IsrDataToPrg_64=0xffffffffffffffff;
		memcpy(&IsrDataToPrg_64,(char*)(addr+written_size),sizeof(uint64_t));
		if((size-written_size)<=sizeof(uint64_t))
		{
			while(i < (size-written_size) )
			{
				*(uint8_t *)((uint32_t)&IsrDataToPrg_64 + i) = *(uint8_t *)buf;
				buf++;
				i++;
			}
			if ((HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr+written_size, IsrDataToPrg_64)) == HAL_OK)
			{
				if(*(uint64_t *)(addr+written_size) != IsrDataToPrg_64)
				{
                    result = FLASH_ERR;
                    break;
                }
			}
			else
            {
                result = FLASH_ERR;
                break;
            }
			write_size=(size-written_size);
		}
		else
		{
			while(i < sizeof(uint64_t) )
			{
				*(uint8_t *)((uint32_t)&IsrDataToPrg_64 + i) = *(uint8_t *)buf;
				buf++;
				i++;
			}
			if ((HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr+written_size, IsrDataToPrg_64)) == HAL_OK)
			{
				if(*(uint64_t *)(addr+written_size) != IsrDataToPrg_64)
				{
                    result = FLASH_ERR;
                    break;
                }
			}
			else
            {
                result = FLASH_ERR;
                break;
            }
			write_size=i;
		}
		written_size += write_size;
	}
#endif
#ifdef CHIP_TYPE_L1
	uint32_t IsrDataToPrg_32=0xffffffff;
	int i=0;
	HAL_StatusTypeDef state;
	while (written_size < size)
	{
		i=0;
		IsrDataToPrg_32=0xffffffff;
		memcpy(&IsrDataToPrg_32,(char*)(addr+written_size),sizeof(uint32_t));
		if((size-written_size)<=sizeof(uint32_t))
		{
			while(i < (size-written_size) )
			{
				*(uint8_t *)((uint32_t)&IsrDataToPrg_32 + i) = *(uint8_t *)buf;
				buf++;
				i++;
			}
			if(addr+written_size>=DATA_EEPROM_START_ADDR&&
				addr+written_size<=DATA_EEPROM_END_ADDR)
			{
				state=HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAM_WORD, addr+written_size, IsrDataToPrg_32);
			}
			else
				state=HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr+written_size, IsrDataToPrg_32);
			if (state == HAL_OK)
			{
				if(*(uint32_t *)(addr+written_size) != IsrDataToPrg_32)
				{
                    result = FLASH_ERR;
                    break;
                }
			}
			else
            {
                result = FLASH_ERR;
                break;
            }
			write_size=(size-written_size);
		}
		else
		{
			while(i < sizeof(uint32_t) )
			{
				*(uint8_t *)((uint32_t)&IsrDataToPrg_32 + i) = *(uint8_t *)buf;
				buf++;
				i++;
			}
			if(addr+written_size>=DATA_EEPROM_START_ADDR&&
				addr+written_size<=DATA_EEPROM_END_ADDR)
			{
				state=HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAM_WORD, addr+written_size, IsrDataToPrg_32);
			}
			else
				state=HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr+written_size, IsrDataToPrg_32);
			if (state == HAL_OK)
			{
				if(*(uint32_t *)(addr+written_size) != IsrDataToPrg_32)
				{
                    result = FLASH_ERR;
                    break;
                }
			}
			else
            {
                result = FLASH_ERR;
                break;
            }
			write_size=i;
		}
		written_size += write_size;
	}
#endif
#ifdef CHIP_TYPE_L1
	if(addr+written_size>=DATA_EEPROM_START_ADDR&&
				addr+written_size<=DATA_EEPROM_END_ADDR)
	{
		HAL_FLASHEx_DATAEEPROM_Lock();
	}
#else
	HAL_FLASH_Lock();
#endif
	__enable_irq();

    if (result != FLASH_OK)
    {
        return result;
    }

    return result;
}

/**
 * Erase data on flash.
 * @note This operation is irreversible.
 * @note This operation's units is different which on many chips.
 *
 * @param addr flash address
 * @param size erase bytes size
 *
 * @return result
 */
int stm32_flash_erase(uint32_t addr, size_t size)
{
	int result = FLASH_OK;
	FLASH_EraseInitTypeDef EraseInitStruct;
	uint32_t SECTORError = 0;
	uint32_t FirstSector = 0, NbOfSectors = 0;

	if ((addr + size) > STM32_FLASH_END_ADDRESS)
    {
        return FLASH_ERR;
    }
    if (size < 1)
    {
        return FLASH_ERR;
    }
	 __disable_irq();
#ifdef CHIP_TYPE_L1
	if(addr>=DATA_EEPROM_START_ADDR&&
				addr<=DATA_EEPROM_END_ADDR)
	{
		HAL_FLASHEx_DATAEEPROM_Unlock();
	}
#else
	HAL_FLASH_Unlock();
#endif

#ifdef CHIP_TYPE_F4	
    /* Unlock the Flash to enable the flash control register access */

    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR);

    /* Get the 1st sector to erase */
    FirstSector = GetSector(addr);
    /* Get the number of sector to erase from 1st sector*/
    NbOfSectors = GetSector(addr + size - 1) - FirstSector + 1;
    /* Fill EraseInit structure*/
    EraseInitStruct.TypeErase     = FLASH_TYPEERASE_SECTORS;
    EraseInitStruct.VoltageRange  = FLASH_VOLTAGE_RANGE_3;
    EraseInitStruct.Sector        = FirstSector;
    EraseInitStruct.NbSectors     = NbOfSectors;
#endif
#ifdef CHIP_TYPE_L4
	__HAL_FLASH_CLEAR_FLAG(	FLASH_FLAG_OPERR |\
							FLASH_FLAG_PROGERR |\
							FLASH_FLAG_WRPERR |\
							FLASH_FLAG_PGAERR |\
							FLASH_FLAG_SIZERR |\
							FLASH_FLAG_PGSERR |\
							FLASH_FLAG_MISERR |\
							FLASH_FLAG_FASTERR |\
							FLASH_FLAG_RDERR |\
							FLASH_FLAG_OPTVERR
	);
    FirstSector = GetPage(addr);
    NbOfSectors = GetNPage(addr, size);
    EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
    EraseInitStruct.Banks       = GetBank(addr);
    EraseInitStruct.Page        = FirstSector;
    EraseInitStruct.NbPages     = NbOfSectors;
#endif
#ifdef CHIP_TYPE_L1
	HAL_StatusTypeDef state;
	__HAL_FLASH_CLEAR_FLAG(	FLASH_FLAG_WRPERR |\
							FLASH_FLAG_PGAERR |\
							FLASH_FLAG_SIZERR |\
							FLASH_FLAG_OPTVERR
	);
   
    NbOfSectors = GetNPage(addr, size);
	FirstSector=0;
    EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
    EraseInitStruct.PageAddress = addr&0xFFFFFF00;
    EraseInitStruct.NbPages     = NbOfSectors+FirstSector;
	if(EraseInitStruct.PageAddress>=DATA_EEPROM_START_ADDR&&
				EraseInitStruct.PageAddress<=DATA_EEPROM_END_ADDR)
	{
		state=HAL_FLASHEx_DATAEEPROM_Erase(FLASH_TYPEERASE_PAGES,EraseInitStruct.PageAddress);
	}
	else
	{
		state=HAL_FLASHEx_Erase(&EraseInitStruct, (uint32_t *)&SECTORError);
	}
	if ( state!= HAL_OK)
    {
        result = FLASH_ERR;
        goto __exit;
    }
#else
	if ( HAL_FLASHEx_Erase(&EraseInitStruct, (uint32_t *)&SECTORError)!= HAL_OK)
    {
        result = FLASH_ERR;
        goto __exit;
    }
#endif
__exit:
#ifdef CHIP_TYPE_L1
	if(addr>=DATA_EEPROM_START_ADDR&&
				addr<=DATA_EEPROM_END_ADDR)
	{
		HAL_FLASHEx_DATAEEPROM_Lock();
	}
#else
	HAL_FLASH_Lock();
#endif    
    __enable_irq();
    if (result != FLASH_OK)
    {
        return result;
    }

    return result;
}



























